<?php

/**
 * SimpleCaptcha class
 *
 */
class framework_base_vcode {

	/** Width of the image */
	public $width = 200;

	/** Height of the image */
	public $height = 70;

	/** Dictionary word file (empty for random text) */
	public $wordsFile = 'files/words/en.php';

	/**
	 * Path for resource files (fonts, words, etc.)
	 *
	 * "resources" by default. For security reasons, is better move this
	 * directory to another location outise the web server
	 *
	 */
	public $resourcesPath = WEB_ROOT;

	/** Min word length (for non-dictionary random text generation) */
	public $minWordLength = 4;

	/**
	 * Max word length (for non-dictionary random text generation)
	 *
	 * Used for dictionary words indicating the word-length
	 * for font-size modification purposes
	 */
	public $maxWordLength = 4;

	/** Sessionname to store the original text */
	public $session_var = 'captcha';

	/** Background color in RGB-array */
	public $backgroundColor = array(
		255,
		255,
		255
	);

	/** Foreground colors in RGB-array */
	public $colors = array(
		array(
			27,
			78,
			181
		), // blue
		array(
			22,
			163,
			35
		), // green
		array(
			214,
			36,
			7
		), // red
	);

	/** Shadow color in RGB-array or null */
	public $shadowColor = null;
	//array(0, 0, 0);

	/** Horizontal line through the text */
	public $lineWidth = 0;

	/**
	 * Font configuration
	 *
	 * - font: TTF file
	 * - spacing: relative pixel space between character
	 * - minSize: min font size
	 * - maxSize: max font size
	 */
	public $fonts = array(
		'Antykwa' => array(
			'spacing' => -3,
			'minSize' => 27,
			'maxSize' => 30,
			'font' => 'AntykwaBold.ttf'
		),
		// 'Candice'  => array('spacing' =>-1.5,'minSize' => 28, 'maxSize' => 31, 'font' => 'Candice.ttf'),
		// 'DingDong' => array('spacing' => -2, 'minSize' => 24, 'maxSize' => 30, 'font' => 'Ding-DongDaddyO.ttf'),
		'Duality' => array(
			'spacing' => -2,
			'minSize' => 30,
			'maxSize' => 38,
			'font' => 'Duality.ttf'
		),
		'Heineken' => array(
			'spacing' => -2,
			'minSize' => 24,
			'maxSize' => 34,
			'font' => 'Heineken.ttf'
		),
		//  'Jura'     => array('spacing' => -2, 'minSize' => 28, 'maxSize' => 32, 'font' => 'Jura.ttf'),
		// 'StayPuft' => array('spacing' =>-1.5,'minSize' => 28, 'maxSize' => 32, 'font' => 'StayPuft.ttf'),
		//'Times' => array('spacing' => -2,'minSize' => 28,'maxSize' => 34,'font' => 'TimesNewRomanBold.ttf'),
		'VeraSans' => array(
			'spacing' => -1,
			'minSize' => 20,
			'maxSize' => 28,
			'font' => 'VeraSansBold.ttf'
		),
	);

	/** Wave configuracion in X and Y axes */
	public $Yperiod = 12;
	public $Yamplitude = 14;
	public $Xperiod = 11;
	public $Xamplitude = 5;

	/** letter rotation clockwise */
	public $maxRotation = 8;

	/**
	 * Internal image size factor (for better image quality)
	 * 1: low, 2: medium, 3: high
	 */
	public $scale = 1;

	/**
	 * Blur effect for better image quality (but slower image processing).
	 * Better image results with scale=3
	 */
	public $blur = false;

	/** Debug? */
	public $debug = false;

	/** Image format: jpeg or png */
	public $imageFormat = 'png';

	/** GD image */
	public $im;

	public function __construct($config = array()) {
	}

	public function CreateImage() {
		ob_clean();
		// $wordsfile = $this -> resourcesPath . '/' . $this -> wordsFile;
		$ini = microtime(true);

		/** Initialization */
		$this -> ImageAllocate();

		/** Text insertion */
		$text = $this -> GetCaptchaText();
		$fontcfg = $this -> fonts[array_rand($this -> fonts)];
		$this -> WriteText($text, $fontcfg);
		$_SESSION[$this -> session_var] = $text;
		//setcookie($this -> session_var,$text,time()+120);
		/** Transformations */
		if (!empty($this -> lineWidth)) {
			$this -> WriteLine();
		}
		$this -> WaveImage();
		if ($this -> blur && function_exists('imagefilter')) {
			imagefilter($this -> im, IMG_FILTER_GAUSSIAN_BLUR);
		}
		$this -> ReduceImage();

		if ($this -> debug) {
			imagestring($this -> im, 1, 1, $this -> height - 8, "$text {$fontcfg['font']} " . round((microtime(true) - $ini) * 1000) . "ms", $this -> GdFgColor);
		}

		/** Output */
		$this -> WriteImage();
		$this -> Cleanup();
	}
    
    //优化验证码识别，author：liuli 2014/0418
    public function CreateImageNew() {
        ob_clean();
        // $wordsfile = $this -> resourcesPath . '/' . $this -> wordsFile;
        $ini = microtime(true);

        /** Initialization */
        $this -> ImageAllocate();

        /** Text insertion */
        $text = $this -> GetCaptchaText();
        $fontcfg = $this -> fonts[array_rand($this -> fonts)];
        $this -> WriteText($text, $fontcfg);
        $_SESSION[$this -> session_var] = $text;
        /** Transformations */
        if (!empty($this -> lineWidth)) {
            $this -> WriteTwoLine();
        }
        $this -> WaveImage();
        if ($this -> blur && function_exists('imagefilter')) {
            imagefilter($this -> im, IMG_FILTER_GAUSSIAN_BLUR);
        }
        $this -> ReduceImage();

        if ($this -> debug) {
            imagestring($this -> im, 1, 1, $this -> height - 8, "$text {$fontcfg['font']} " . round((microtime(true) - $ini) * 1000) . "ms", $this -> GdFgColor);
        }

        /** Output */
        $this -> WriteImage();
        $this -> Cleanup();
    }
    

	/**
	 * Creates the image resources
	 */
	protected function ImageAllocate() {
		// Cleanup
		if (!empty($this -> im)) {
			imagedestroy($this -> im);
		}

		$this -> im = imagecreatetruecolor($this -> width * $this -> scale, $this -> height * $this -> scale);

		// Background color
		$this -> GdBgColor = imagecolorallocate($this -> im, $this -> backgroundColor[0], $this -> backgroundColor[1], $this -> backgroundColor[2]);
		imagefilledrectangle($this -> im, 0, 0, $this -> width * $this -> scale, $this -> height * $this -> scale, $this -> GdBgColor);

		// Foreground color
		$color = $this -> colors[mt_rand(0, sizeof($this -> colors) - 1)];
		$this -> GdFgColor = imagecolorallocate($this -> im, $color[0], $color[1], $color[2]);

		// Shadow color
		if (!empty($this -> shadowColor) && is_array($this -> shadowColor) && sizeof($this -> shadowColor) >= 3) {
			$this -> GdShadowColor = imagecolorallocate($this -> im, $this -> shadowColor[0], $this -> shadowColor[1], $this -> shadowColor[2]);
		}
	}

	/**
	 * Text generation
	 *
	 * @return string Text
	 */
	protected function GetCaptchaText() {
		// $text = $this->GetDictionaryCaptchaText();
		$text = false;
		if (!$text) {
			$text = $this -> GetRandomCaptchaText();
		}
		return $text;
	}

	/**
	 * Random text generation
	 *
	 * @return string Text
	 */
	protected function GetRandomCaptchaText($length = null) {
		if (empty($length)) {
			$length = rand($this -> minWordLength, $this -> maxWordLength);
		}

		$words = "abcdefghijlmnopqrstvwyz";
		$vocals = "aeiou";

		$text = "";
		$vocal = rand(0, 1);
		for ($i = 0; $i < $length; $i++) {
			if ($vocal) {
				$text .= substr($vocals, mt_rand(0, 4), 1);
			} else {
				$text .= substr($words, mt_rand(0, 22), 1);
			}
			$vocal = !$vocal;
		}
		return $text;
	}

	/**
	 * Random dictionary word generation
	 *
	 * @param boolean $extended Add extended "fake" words
	 * @return string Word
	 */
	function GetDictionaryCaptchaText($extended = false) {
		if (empty($this -> wordsFile)) {
			return false;
		}

		// Full path of words file
		if (substr($this -> wordsFile, 0, 1) == '/') {
			$wordsfile = $this -> wordsFile;
		} else {
			$wordsfile = $this -> resourcesPath . '/' . $this -> wordsFile;
		}
		if (!file_exists($wordsfile)) {
			return false;
		}

		$fp = fopen($wordsfile, "r");
		$length = strlen(fgets($fp));
		if (!$length) {
			return false;
		}
		$line = rand(1, (filesize($wordsfile) / $length) - 2);
		if (fseek($fp, $length * $line) == -1) {
			return false;
		}
		$text = trim(fgets($fp));
		fclose($fp);

		/** Change ramdom volcals */
		if ($extended) {
			$text = preg_split('//', $text, -1, PREG_SPLIT_NO_EMPTY);
			$vocals = array(
				'a',
				'e',
				'i',
				'o',
				'u'
			);
			foreach ($text as $i => $char) {
				if (mt_rand(0, 1) && in_array($char, $vocals)) {
					$text[$i] = $vocals[mt_rand(0, 4)];
				}
			}
			$text = implode('', $text);
		}

		return $text;
	}

	/**
	 * Horizontal line insertion
	 */
	protected function WriteLine() {

		$x1 = $this -> width * $this -> scale * .15;
		$x2 = $this -> textFinalX;
		$y1 = rand($this -> height * $this -> scale * .40, $this -> height * $this -> scale * .65);
		$y2 = rand($this -> height * $this -> scale * .40, $this -> height * $this -> scale * .65);
		$width = $this -> lineWidth / 2 * $this -> scale;

		for ($i = $width * -1; $i <= $width; $i++) {
			imageline($this -> im, $x1, $y1 + $i, $x2, $y2 + $i, $this -> GdFgColor);
		}
	}
    
    /**
     * 干扰曲线
     * author:liuli 
     * Horizontal line insertion [Two]
     */
   protected function WriteTwoLine() {

        $x1 = $this -> width * $this -> scale * .15;
        $x2 = $this -> textFinalX;
        $y1 = rand($this -> height * $this -> scale * .40, $this -> height * $this -> scale * .65);
        $y2 = rand($this -> height * $this -> scale * .40, $this -> height * $this -> scale * .65);
        $width = $this -> lineWidth / 2 * $this -> scale;
        
        $m = rand(2,5);
        for ($i = $width * -1; $i <= $width; $i++) {
            imageline($this -> im, $x1, $y1 + $i, $x2, $y2 + $i, $this -> GdFgColor);
            imageline($this -> im, $x1/$m, ($y1 + $i)/$m, $x2*$m, ($y2 + $i)*$m, $this -> GdBgColor);
        }
    }

	/**
	 * Text insertion
	 */
	protected function WriteText($text, $fontcfg = array()) {
		if (empty($fontcfg)) {
			// Select the font configuration
			$fontcfg = $this -> fonts[array_rand($this -> fonts)];
		}

		// Full path of font file
		$fontfile = $this -> resourcesPath . '/files/font/' . $fontcfg['font'];
		// var_dump(file_exists($fontfile));
		// echo $fontfile;
		// exit ;

		/** Increase font-size for shortest words: 9% for each glyp missing */
		$lettersMissing = $this -> maxWordLength - strlen($text);
		$fontSizefactor = 1 + ($lettersMissing * 0.09);

		// Text generation (char by char)
		$x = 20 * $this -> scale;
		$y = round(($this -> height * 27 / 40) * $this -> scale);
		$length = strlen($text);
		for ($i = 0; $i < $length; $i++) {
			$degree = rand($this -> maxRotation * -1, $this -> maxRotation);
			$fontsize = rand($fontcfg['minSize'], $fontcfg['maxSize']) * $this -> scale * $fontSizefactor;
			$letter = substr($text, $i, 1);

			if ($this -> shadowColor) {
				$coords = imagettftext($this -> im, $fontsize, $degree, $x + $this -> scale, $y + $this -> scale, $this -> GdShadowColor, $fontfile, $letter);
			}
			$coords = imagettftext($this -> im, $fontsize, $degree, $x, $y, $this -> GdFgColor, $fontfile, $letter);
			$x += ($coords[2] - $x) + ($fontcfg['spacing'] * $this -> scale);
		}

		$this -> textFinalX = $x;
	}

	/**
	 * Wave filter
	 */
	protected function WaveImage() {
		// X-axis wave generation
		$xp = $this -> scale * $this -> Xperiod * rand(1, 3);
		$k = rand(0, 100);
		for ($i = 0; $i < ($this -> width * $this -> scale); $i++) {
			imagecopy($this -> im, $this -> im, $i - 1, sin($k + $i / $xp) * ($this -> scale * $this -> Xamplitude), $i, 0, 1, $this -> height * $this -> scale);
		}

		// Y-axis wave generation
		$k = rand(0, 100);
		$yp = $this -> scale * $this -> Yperiod * rand(1, 2);
		for ($i = 0; $i < ($this -> height * $this -> scale); $i++) {
			imagecopy($this -> im, $this -> im, sin($k + $i / $yp) * ($this -> scale * $this -> Yamplitude), $i - 1, 0, $i, $this -> width * $this -> scale, 1);
		}
	}

	/**
	 * Reduce the image to the final size
	 */
	protected function ReduceImage() {
		$imResampled = imagecreatetruecolor($this -> width, $this -> height);
		imagecopyresampled($imResampled, $this -> im, 0, 0, 0, 0, $this -> width, $this -> height, $this -> width * $this -> scale, $this -> height * $this -> scale);
		imagedestroy($this -> im);
		$this -> im = $imResampled;
	}

	/**
	 * File generation
	 */
	protected function WriteImage() {
		if ($this -> imageFormat == 'png' && function_exists('imagepng')) {
			header("Content-type: image/png");
			imagepng($this -> im);
		} else {
			header("Content-type: image/jpeg");
			imagejpeg($this -> im, null, 80);
		}
	}

	/**
	 * Cleanup
	 */
	protected function Cleanup() {
		imagedestroy($this -> im);
	}

}
?>